function Person(data) {
    this.id = ko.observable(data.id);
    this.firstName = ko.observable(data.firstName);
    this.lastName = ko.observable(data.lastName);
    this.description = ko.observable(data.description);
    this.addresses = ko.observable(data.addresses);
    this.phoneNumbers = ko.observable(data.phoneNumbers);

    this.fullName = ko.computed(function () {
        return this.firstName() + ' ' + this.lastName();
    }, this);
}

function Address(data) {
    this.id = ko.observable(data.id);
    this.city = ko.observable(data.city);
    this.street = ko.observable(data.street);
    this.building = ko.observable(data.building);
    this.apartment = ko.observable(data.apartment);

    this.fullAddress = ko.computed(function () {
        return this.city() + ', ' + this.street() + ' ' + this.building() + ', ' + this.apartment();
    }, this);
}

function PhoneNumber(data) {
    this.id = ko.observable(data.id);
    this.code = ko.observable(data.code);
    this.number = ko.observable(data.number);
    this.phoneType = ko.observable(data.phoneType);
}

function PersonViewModel() {
    var self = this;
    self.a = ko.observable(false);
    self.b = ko.observable(false);
    self.modeChooser = ko.observable(0);
    self.current = new Person({firstName: '', lastName: '', description: ''});

    // Person data
    self.personId = ko.observable();
    self.firstName = ko.observable();
    self.lastName = ko.observable();
    self.description = ko.observable();

    self.addresses = ko.observableArray([]);
    self.phoneNumbers = ko.observableArray([]);

    //  Address
    self.city = ko.observable();
    self.street = ko.observable();
    self.building = ko.observable();
    self.apartment = ko.observable();

    // Phone Number
    self.code = ko.observable();
    self.number = ko.observable();
    self.phoneType = ko.observable();

    //Persons list
    self.personList = ko.observableArray([]);

    //Search field value
    self.searchField = ko.observable();

    //Mail validator
    self.mailIsValid = ko.observable();

    self.addPerson = function () {
        $.ajax({
            type: 'put',
            url: '/services/rest/person',
            contentType: 'application/json',
            dataType: 'json',
            data: ko.toJSON({
                firstName: self.firstName(),
                lastName: self.lastName(),
                description: self.description()
            }),
            success: function (data) {
                console.log('person with id = ' + data.id + ' added');
                self.personId(data.id);
            }
        });
    };

    self.modifyPerson = function () {
        $.ajax({
            type: 'post',
            url: '/services/rest/person',
            contentType: 'application/json',
            dataType: 'json',
            data: ko.toJSON({
                id: self.personId(),
                firstName: self.firstName(),
                lastName: self.lastName(),
                description: self.description()
            }),
            success: function () {
                console.log('person with id = ' + self.personId() + ' modified');
            }
        });
    };

    self.addAddress = function () {
        $.ajax({
            type: 'put',
            contentType: 'application/json',
            url: '/services/rest/address/' + self.personId(),
            data: ko.toJSON({
                city: self.city(),
                street: self.street(),
                building: self.building(),
                apartment: self.apartment()
            }),
            success: function (data) {
                self.addresses.push(new Address(data))
            }
        });
        self.city("");
        self.street("");
        self.building("");
        self.apartment("");
    };

    self.removeAddress = function (address) {
        $.ajax({
            type: 'delete',
            url: '/services/rest/address/' + self.personId() + '/' + address.id(),
            success: function () {
                self.addresses.destroy(address);
            }
        });
    };

    self.addPhoneNumber = function () {
        $.ajax({
            type: 'put',
            contentType: 'application/json',
            url: '/services/rest/phone/' + self.personId(),
            data: ko.toJSON({
                code: self.code(),
                number: self.number()
            }),
            success: function (data) {
                self.phoneNumbers.push(new PhoneNumber(data))
            }
        });
        self.code("");
        self.number("");
    };

    self.removePhoneNumber = function (number) {
        $.ajax({
            type: 'delete',
            url: '/services/rest/phone/' + number.id(),
            success: function () {
                self.phoneNumbers.destroy(number);
            }
        });
    };

    self.loadPersons = function () {
        $.ajax({
            type: 'get',
            url: '/services/rest/person',
            contentType: 'application/json',
            dataType: 'json',
            success: function (data) {
                var mappedPersons = $.map(data, function (item) {
                    return new Person(item)
                });
                self.personList(mappedPersons);
            }
        });
    };

    self.loadFullPerson = function (person) {
        $.ajax({
            type: 'get',
            url: '/services/rest/person/full/' + person.id(),
            contentType: 'application/json',
            dataType: 'json',
            success: function (data) {
                self.personId(data.id);
                self.firstName(data.firstName);
                self.lastName(data.lastName);
                self.description(data.description);

                var mappedAddresses = $.map(data.addresses, function (item) {
                    return new Address(item);
                });
                var mappedPhones = $.map(data.phoneNumbers, function (item) {
                    return new PhoneNumber(item);
                });

                self.addresses(mappedAddresses);
                self.phoneNumbers(mappedPhones);
            }
        });
    };

    self.ensureUniqueMail = function (newValue) {
        $.ajax({
            type: 'get',
            url: '/services/rest/person/mail/' + newValue,
            success: function (data) {
                self.mailIsValid(data);
            }
        })
    };

    self.emptyMode = function () {
        self.modeChooser(0);
    };

    self.createMode = function () {
        self.modeChooser(1);
    };

    self.editMode = function () {
        self.modeChooser(2);
    };

    self.switchAddAddress = function () {
        self.a(!self.a());
    };

    self.switchAddPhone = function () {
        self.b(!self.b());
    };

    self.erasePersonModel = function () {
        self.personId("");
        self.firstName("");
        self.lastName("");
        self.description("");
        self.addresses([]);
        self.phoneNumbers([]);
    };

    self.modelIsChanged = ko.computed(function () {
        return !((self.current.firstName() == self.firstName())
            && (self.current.lastName() == self.lastName())
            && (self.current.description() == self.description()));
    });

    self.loadPersonsHandler = function () {
        self.emptyMode();
        self.loadPersons();
    };

    self.editHandler = function (person) {
        self.editMode();
        self.loadFullPerson(person);
        self.current = person;
        console.log(person.firstName() + ' ' + person.lastName())
    };

    self.addAddressHandler = function () {
        self.switchAddAddress();
        self.addAddress();
    };

    self.addPhoneHandler = function () {
        self.switchAddPhone();
        self.addPhoneNumber();
    };

    self.newPersonHandler = function () {
        self.erasePersonModel();
        self.createMode();
    };

    self.createPersonHandler = function () {
        self.addPerson();
        self.editMode();
    };

    self.cancelCreateHandler = function () {
        self.emptyMode();
        self.erasePersonModel();
    };

    self.cancelEditing = function () {
        self.loadFullPerson({id: self.personId});
    };

    self.saveHandler = function () {
        self.modifyPerson();
        self.current.firstName(self.firstName());
        self.current.lastName(self.lastName());
        self.current.description(self.description());
    };

    self.checkValidMail = function (mail) {
        if (self.current.description() == mail) {
            self.mailIsValid('Current using');
        }
        if (mailRegexp.test(self.description())) {
            self.ensureUniqueMail(mail);
        } else {
            self.mailIsValid('Invalid value');
        }
    };
}

var nameRegexp = /[A-Z]+[a-z]+/;
var mailRegexp = /[0-9a-z_.]+@[a-z]+\.[a-z]{2,4}/;
var viewModel = new PersonViewModel();

viewModel.description.subscribe(viewModel.checkValidMail);

function loadKO() {
    ko.applyBindings(viewModel);
}

window.onload = loadKO;

